﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace KinectAPI.Gestures.NDollar
{
    public class NDollar : KinectAPI.Gesture
    {
        private BodyTracker body;
        private BodyGestureGenerator bgg;
        private Dictionary<uint, Dictionary<string, List<PointR>>> users;

        private const int MinNoPoints = 70;
        private GeometricRecognizer _rec;

        public event EventHandler Start;

        public event EventHandler End;

        public event EventHandler Recognised;

        public string getName()
        {
            return "NDollar";
        }

        public NDollar()
        {
        }

        public void construct(object[] args)
        {
            bgg = (BodyGestureGenerator)args[1];
            body = (BodyTracker)args[0];
            body.UsersUpdated += new BodyTracker.UsersUpdatedHandler(Users_Updated);

            _rec = new GeometricRecognizer();
            LoadGesture((string[])args[2]);

            users = new Dictionary<uint, Dictionary<string, List<PointR>>>();
        }

        void LoadGesture(string[] args)
        {
            bool all = false;
            if (args[0].CompareTo("All") == 0)
            {
                all = true;
            }
            DirectoryInfo info = new DirectoryInfo(@"..\..\plugins\xml$N");
            foreach (DirectoryInfo dir in info.GetDirectories())
            {
                foreach (FileInfo file in dir.GetFiles("*.xml"))
                {
                    if (all || args.Contains(file.Name.Substring(0, file.Name.Length - 4)))
                    {
                        System.Console.WriteLine("load " + dir.Name + "\\" + file.Name);
                        _rec.LoadGesture(file.FullName);
                    }
                }
            }
        }

        void Users_Updated(object sender, UsersEventArgs e)
        {
            if (_rec.NumGestures > 0)
            {
                foreach (var user in e.users)
                {
                    #region create if new user

                    if (!users.ContainsKey(user.Id))
                    {
                        Dictionary<string, List<PointR>> newUser = new Dictionary<string, List<PointR>>();
                        newUser.Add("Head", new List<PointR>());
                        newUser.Add("Neck", new List<PointR>());
                        newUser.Add("LeftShoulder", new List<PointR>());
                        newUser.Add("LeftElbow", new List<PointR>());
                        newUser.Add("LeftHand", new List<PointR>());
                        newUser.Add("RightShoulder", new List<PointR>());
                        newUser.Add("RightElbow", new List<PointR>());
                        newUser.Add("RightHand", new List<PointR>());
                        newUser.Add("Torso", new List<PointR>());
                        newUser.Add("LeftHip", new List<PointR>());
                        newUser.Add("LeftKnee", new List<PointR>());
                        newUser.Add("LeftFoot", new List<PointR>());
                        newUser.Add("RightHip", new List<PointR>());
                        newUser.Add("RightKnee", new List<PointR>());
                        newUser.Add("RightFoot", new List<PointR>());
                        users.Add(user.Id, newUser);
                    }

                    #endregion

                    #region Remove first if list full

                    if (users[user.Id]["Head"].Count() == MinNoPoints)
                    {
                        users[user.Id]["Head"].RemoveAt(0);
                        users[user.Id]["Neck"].RemoveAt(0);
                        users[user.Id]["LeftShoulder"].RemoveAt(0);
                        users[user.Id]["LeftElbow"].RemoveAt(0);
                        users[user.Id]["LeftHand"].RemoveAt(0);
                        users[user.Id]["RightShoulder"].RemoveAt(0);
                        users[user.Id]["RightElbow"].RemoveAt(0);
                        users[user.Id]["RightHand"].RemoveAt(0);
                        users[user.Id]["Torso"].RemoveAt(0);
                        users[user.Id]["LeftHip"].RemoveAt(0);
                        users[user.Id]["LeftKnee"].RemoveAt(0);
                        users[user.Id]["LeftFoot"].RemoveAt(0);
                        users[user.Id]["RightHip"].RemoveAt(0);
                        users[user.Id]["RightKnee"].RemoveAt(0);
                        users[user.Id]["RightFoot"].RemoveAt(0);
                    }

                    #endregion

                    #region Add the new points

                    users[user.Id]["Head"].Add(new PointR(user.Head.X, user.Head.Y, Environment.TickCount));
                    users[user.Id]["Neck"].Add(new PointR(user.Neck.X, user.Neck.Y, Environment.TickCount));
                    users[user.Id]["LeftShoulder"].Add(new PointR(user.LeftShoulder.X, user.LeftShoulder.Y, Environment.TickCount));
                    users[user.Id]["LeftElbow"].Add(new PointR(user.LeftElbow.X, user.LeftElbow.Y, Environment.TickCount));
                    users[user.Id]["LeftHand"].Add(new PointR(user.LeftHand.X, user.LeftHand.Y, Environment.TickCount));
                    users[user.Id]["RightShoulder"].Add(new PointR(user.RightShoulder.X, user.RightShoulder.Y, Environment.TickCount));
                    users[user.Id]["RightElbow"].Add(new PointR(user.RightElbow.X, user.RightElbow.Y, Environment.TickCount));
                    users[user.Id]["RightHand"].Add(new PointR(user.RightHand.X, user.RightHand.Y, Environment.TickCount));
                    users[user.Id]["Torso"].Add(new PointR(user.Torso.X, user.Torso.Y, Environment.TickCount));
                    users[user.Id]["LeftHip"].Add(new PointR(user.LeftHip.X, user.LeftHip.Y, Environment.TickCount));
                    users[user.Id]["LeftKnee"].Add(new PointR(user.LeftKnee.X, user.LeftKnee.Y, Environment.TickCount));
                    users[user.Id]["LeftFoot"].Add(new PointR(user.LeftFoot.X, user.LeftFoot.Y, Environment.TickCount));
                    users[user.Id]["RightHip"].Add(new PointR(user.RightHip.X, user.RightHip.Y, Environment.TickCount));
                    users[user.Id]["RightKnee"].Add(new PointR(user.RightKnee.X, user.RightKnee.Y, Environment.TickCount));
                    users[user.Id]["RightFoot"].Add(new PointR(user.RightFoot.X, user.RightFoot.Y, Environment.TickCount));

                    #endregion

                    #region Recognition

                    if (users[user.Id]["Head"].Count > 40)
                    {

                        List<PointR> points = new List<PointR>();
                        foreach (KeyValuePair<string, List<PointR>> pair in users[user.Id])
                        {
                            points.AddRange(pair.Value);
                        }
                        // where all the action is!!
                        NBestList result = _rec.Recognize(points, 15);

                        if (result.Score >= 0.70)
                        {
                            #region Clear User lists

                            users[user.Id]["Head"].Clear();
                            users[user.Id]["Neck"].Clear();
                            users[user.Id]["LeftShoulder"].Clear();
                            users[user.Id]["LeftElbow"].Clear();
                            users[user.Id]["LeftHand"].Clear();
                            users[user.Id]["RightShoulder"].Clear();
                            users[user.Id]["RightElbow"].Clear();
                            users[user.Id]["RightHand"].Clear();
                            users[user.Id]["Torso"].Clear();
                            users[user.Id]["LeftHip"].Clear();
                            users[user.Id]["LeftKnee"].Clear();
                            users[user.Id]["LeftFoot"].Clear();
                            users[user.Id]["RightHip"].Clear();
                            users[user.Id]["RightKnee"].Clear();
                            users[user.Id]["RightFoot"].Clear();

                            #endregion

                            // Generate the event
                            Recognised(this, new GestureEventArgs(getName(), new object[] { user.Id, result.Name, result.Score }));
                        }
                    }

                    #endregion
                }
            }
        }

        //// event handler for the Record button
        //// Lisa 1/2/2008
        //private void RecordButton_Click(object sender, EventArgs e)
        //{
        //    SaveFileDialog dlg = new SaveFileDialog();
        //    dlg.Filter = "Gestures (*.xml)|*.xml";
        //    dlg.Title = "Save Gesture As";
        //    dlg.AddExtension = true;
        //    dlg.RestoreDirectory = true; // Lisa 8/16/2009; have to un-allow this because of accessing our parameters config file

        //    if (dlg.ShowDialog(this) == DialogResult.OK)
        //    {
        //        // resample, scale, translate to origin
        //        _rec.SaveGesture(dlg.FileName, _strokes, _numPtsInStroke);  // strokes, not points; Lisa 8/8/2009 
        //        ReloadViewForm();
        //    }

        //    dlg.Dispose();
        //    _recording = false;
        //    lblRecord.Visible = false;
        //    recognizeButton.Enabled = true; // this wasn't enabled while we were recording
        //    Invalidate();
        //}
    }
}
